from abc import ABC, abstractmethod, abstractproperty
from typing import Dict, List, Tuple, Union

T = Union[str, bytes]


class BaseTokenizer(ABC):
    """
    分词器的同一接口
    有如下接口:
    令牌化函数, 反令牌化函数.
    分词函数, 反分词函数,
    ID化函数, 反ID化函数
    词表数函数, 词表(属性化)函数
    """

    def tokenize(self, line: str) -> Tuple[List[T], List[int]]:
        """
        令牌化函数, 首先把传入的字符串分词为单个的单元(分词)
        接着,将单元(unit)列表逐一令牌化(id化)

        Args:
            line: str

        Returns:
            list_1: 单元列表
            list_2: ID列表

        """
        tokens = self.text2tokens(line)
        ids = self.tokens2ids(tokens)
        return tokens, ids

    def detokenize(self, ids: List[int]) -> Tuple[str, List[T]]:
        """
        反令牌化函数
        传入要反令牌的ID列表, 首先进行反ID化,得到unit-list,
        接着进行反分词化, 将unit-list转为str
        Args:
            ids: list[int]

        Returns:
            str: 结果字符串
            list_unit: 结果 unit-list

        """
        tokens = self.ids2tokens(ids)
        text = self.tokens2text(tokens)
        return text, tokens

    @abstractmethod
    def text2tokens(self, line: str) -> List[T]:
        raise NotImplementedError("abstract method")

    @abstractmethod
    def tokens2text(self, tokens: List[T]) -> str:
        raise NotImplementedError("abstract method")

    @abstractmethod
    def tokens2ids(self, tokens: List[T]) -> List[int]:
        raise NotImplementedError("abstract method")

    @abstractmethod
    def ids2tokens(self, ids: List[int]) -> List[T]:
        raise NotImplementedError("abstract method")

    @abstractmethod
    def vocab_size(self) -> int:
        raise NotImplementedError("abstract method")

    @abstractproperty
    def symbol_table(self) -> Dict[T, int]:
        raise NotImplementedError("abstract method")
